home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
wais
/
ui
/
lisp-ui.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-09
|
10KB
|
374 lines
/* WIDE AREA INFORMATION SERVER SOFTWARE:
No guarantees or restrictions. See the readme file for the full standard
disclaimer.
Brewster@think.com
*/
/* This is a simple wais interface for lisp clients.
* It takes in lisp-y looking requests and sends out Z39.50 packets.
*
* -brewster 7/90
*
* Important functions:
* display_search_response
* main
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "../ir/ui.h"
#define CHARS_PER_PAGE 10000 /* number of chars retrieved in each request */
#define MAX_MESSAGE_LEN BUFSZ
#define VERBOSE false /* true */
/****************************************************************
*
* Function Name: display_search_response
*
*
* Purpose: displays the formatted list of documents in the form
* that the super-text-server would like to see.
*
* Returns: nothing.
*
* Algorithm: . ...
*
*/
/* modified from tracy shen's version in wutil.c
* displays a set of headlines.
*/
void
display_search_response(response,database,server_name,service_name)
SearchResponseAPDU *response;
char *database;
char *server_name;
char *service_name;
{
WAISSearchResponse *info;
long k;
printf("(:query (");
if ( response->DatabaseDiagnosticRecords != 0 ) {
info = response->DatabaseDiagnosticRecords;
if(info->DocHeaders != 0){
k =0;
while(info->DocHeaders[k] != 0 ){
char doc_id[1000];
strncpy(doc_id, info->DocHeaders[k]->DocumentID->bytes,
MIN(info->DocHeaders[k]->DocumentID->size, 1000));
doc_id[MIN(info->DocHeaders[k]->DocumentID->size, 1000 - 1)]
= '\0';
printf("(:doc-id \"%s\" :document-length %ld :types (\"%s\") :database-name \"%s\" :server-name \"%s\" :score %ld :service \"%s\" :header \"",
doc_id,
info->DocHeaders[k]->DocumentLength,
(info->DocHeaders[k]->Types == NULL)?"TEXT":info->DocHeaders[k]->Types[0],
database,
server_name,
info->DocHeaders[k]->Score,
service_name
);
{ char *header = trim_junk(info->DocHeaders[k]->Headline);
long i;
for(i=0; i < strlen(header); i++){
char ch = header[i];
if(ch == '"')
putc('\\', stdout);
putc(ch, stdout);
}
}
printf("\")");
k++;
}
}
}
printf(")\n:end t)\n"); /* finish it */
fflush(stdout);
}
/*******************
* Parsing *
*******************/
/* In a alist of keys and values,
* this finds the string value associated with a key.
* The way this is implemented is a kludge since it searches for
* the key with string search rather than making a list and
* searching down it. This can error if a value contains a string version
* of the key.
* What we really need is list facilities.
*
* Side effects value.
* Returns 0 if it wins, 1 if there is no such slot, -1 if error.
*/
/* these are states of the parser */
#define BEFORE 1
#define DURING 2
#define QUOTE 5
long find_string_slot(source,key,value,value_size,delete_internal_quotes)
char *source;
char *key;
char *value;
long value_size;
boolean delete_internal_quotes;
{
char ch;
short state = BEFORE;
long position = 0; /* position in value */
char *pos =strstr(source, key); /* address into source */
value[0] = '\0'; /* initialize to nothing */
if(NULL == pos)
return(1);
for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
ch = *pos;
if((state == BEFORE) && (ch == '\"'))
state = DURING;
else if ((state == DURING) && (ch == '\\')){
state = QUOTE;
if(!delete_internal_quotes){
value[position] = ch;
position++;
if(position >= value_size){
value[value_size - 1] = '\0';
return(-1);
}
}
}
else if ((state == DURING) && (ch == '"')){
value[position] = '\0';
return(0);
}
else if ((state == QUOTE) || (state == DURING)){
if(state == QUOTE)
state = DURING;
value[position] = ch;
position++;
if(position >= value_size){
value[value_size - 1] = '\0';
return(-1);
}
}
/* otherwise we are still before the start of the value */
}
value[position] = '\0';
return(-1); /* error because we are in the middle of the string */
}
/* reads a long int a file returns true if successful, false otherwise */
long find_long_slot(source,key,answer)
char *source;
char *key;
long *answer;
{
char ch;
short state = BEFORE;
char *pos =strstr(source, key); /* address into source */
long count = 0;
boolean isNegative = false;
*answer = 0;
if(NULL == pos)
return(1);
for(pos = pos + strlen(key); pos < source + strlen(source); pos++){
ch = *pos;
if (isdigit(ch)){
if(state == BEFORE){
state = DURING;
}
count++;
if(count == 12){
/* then we have an error in the file, 32 bit numbers can not be more
than 10 digits long */
return(-1);
}
*answer = *answer * 10 + (ch - '0');
}
else if (ch == '-') {
if (isNegative)
/* then we have an error since there should be only one - in a number */
return(-1);
if (state == BEFORE) {
/* we are ok since the - must come before any digits */
isNegative = true;
state = DURING;
}
else {
break; /* we are done */
}
}
else if(!isspace(ch)){
/* then we have an error since it should be a digit or a space */
return(-1);
}
/* we do not have an digit */
else if(state == DURING){
break; /* we are done */
}
/* otherwise we are still before the start */
}
if (isNegative)
*answer *= -1;
return(0);
}
/************
* MAIN *
************/
#define MAX_QUERY_SIZE 10000
#define MAX_NAME_SIZE 1000
void main()
{
char query[MAX_QUERY_SIZE + 1];
char request_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
char response_message[MAX_MESSAGE_LEN]; /* arbitrary message limit */
long request_buffer_length; /* how of the request is left */
SearchResponseAPDU *query_response;
SearchResponseAPDU *retrieval_response;
char service[MAX_NAME_SIZE + 1];
char database[MAX_NAME_SIZE + 1];
char server_name[MAX_NAME_SIZE + 1];
char type[MAX_NAME_SIZE + 1];
server_name[0] = '\0'; /* null it out */
database[0] = '\0'; /* null it out */
service[0] = '\0'; /* null it out */
while(TRUE){
/* continue to search until the user gets tired */
fgets(query, MAX_QUERY_SIZE, stdin);
if(NULL != strstr(query, ":fill-in") ||
NULL != strstr(query, ":query")){
/* then we have a fill-in or query.
extract the common fields */
if(0 > find_string_slot(query, ":database", database,
MAX_NAME_SIZE, false)){
panic("Could not read the database from query %s", query);
}
if(0 > find_string_slot(query, ":server", server_name,
MAX_NAME_SIZE, false)){
panic("Could not read the host from query %s", query);
}
if(0 > find_string_slot(query, ":service", service,
MAX_NAME_SIZE, false)){
panic("Could not read the service from query %s", query);
}
}
if(NULL != strstr(query, ":fill-in")){
/* then we have a fill-in request */
long count;
long document_length;
char doc_id[MAX_NAME_SIZE + 1];
any doc_id_any;
if(0 != find_string_slot(query, ":doc-id", doc_id,
MAX_NAME_SIZE, false)){
panic("Could not read the doc-id from request %s", query);
}
doc_id_any.bytes = doc_id;
doc_id_any.size = strlen(doc_id);
if(0 != find_long_slot(query, ":document-length", &document_length)){
panic("Could not read the document length from doc_id %s", query);
}
if(0 != find_string_slot(query, ":type", type,
MAX_NAME_SIZE, false)){
panic("Could not read the type from request %s", query);
}
printf("(:fill-in (:text \""); /* start the reply */
for(count = 0;
count * CHARS_PER_PAGE < document_length;
count++){
request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
if(NULL ==
generate_retrieval_apdu(request_message + HEADER_LENGTH,
&request_buffer_length,
&doc_id_any,
CT_byte,
count * CHARS_PER_PAGE,
MIN((count + 1) * CHARS_PER_PAGE,
document_length),
type,
database
))
panic("query was too large");
if(0 ==
interpret_message(request_message,
MAX_MESSAGE_LEN - request_buffer_length,
response_message,
MAX_MESSAGE_LEN,
server_name,
service,
VERBOSE
))
panic("return message too large");
readSearchResponseAPDU(&retrieval_response,
response_message + HEADER_LENGTH);
if(NULL == ((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text)
panic("No text was returned");
display_text_record_completely
(((WAISSearchResponse *)retrieval_response->DatabaseDiagnosticRecords)->Text[0], true);
}
printf("\")\n:end t)\n"); /* finish the text */
fflush(stdout);
}
else if(NULL != strstr(query, ":query")){
/* then we have a query */
char seed_words[MAX_QUERY_SIZE + 1];
if(0 != find_string_slot(query, ":seed-words", seed_words,
MAX_QUERY_SIZE, false)){
panic("Could not read the seed words from query %s", query);
}
request_buffer_length = MAX_MESSAGE_LEN; /* how of the request is left */
if(NULL ==
generate_search_apdu(request_message + HEADER_LENGTH,
&request_buffer_length,
seed_words, database, NULL))
panic("Query was too large");
if(0 ==
interpret_message(request_message,
MAX_MESSAGE_LEN - request_buffer_length,
response_message,
MAX_MESSAGE_LEN,
server_name,
service,
VERBOSE
))
panic("return message too large");
readSearchResponseAPDU(&query_response,
response_message + HEADER_LENGTH);
display_search_response(query_response, database, server_name,
service);
}
else
panic("Dont know how to handle query %s\n", query);
}
}
/* sample
(:query :seed-words ("food") :database "/u/kahle/wais-index-irn8/foo" :server "gandalf" :service "8000")
*/